/*
 * Amkai Enterprise Solution (AES.) 
 * Copyright 2004 by Amkai(TM), Inc.
 * www.amkai.com
 * 
 * Project: webservice
 * Package: com.amkai.aes.webservice.binary.objecthandler.registration
 * File: PatientLabelJobHandler.java
 * Created: 2007.10.30. 16:40:22
 * Author: azalan 
 * 
 */
package com.amkai.aes.webservice.binary.objecthandler.registration;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Query;

import com.amkai.aes.aescommon.service.binary.job.registration.PatientLabelJob;
import com.amkai.aes.aescommon.service.binary.job.registration.PatientLabelJobResult;
import com.amkai.aes.aescommon.service.binary.job.registration.PatientLabelWizardState;
import com.amkai.aes.aescommon.utilities.ItemSeparator;
import com.amkai.aes.webservice.binary.JobObjectHandler;
import com.amkai.common.extensions.hibernate.config.SiteManager;
import com.amkai.common.extensions.hibernate.config.manager.SessionManager;

public class PatientLabelJobHandler implements JobObjectHandler<PatientLabelJob, PatientLabelWizardState, PatientLabelJobResult>{
	private static final Log log = LogFactory.getLog(PatientLabelJobHandler.class);

	@Override
	@SuppressWarnings("unchecked")
	public PatientLabelJobResult process(PatientLabelJob job,
			PatientLabelWizardState state) throws Exception {
		log.debug("");

		PatientLabelJobResult result = new PatientLabelJobResult();
		
		SessionManager sm = SiteManager.Start();
		sm.openSession();
		try {
			QueryBuilder builder = QueryBuilder.buildQuery(state);
			Query query = sm.execute(builder.getQueryStr());
			int cnt = 0;
			for (Object param : builder.getQueryParams()) {
				query.setParameter(cnt++, param);
			}
			result.setPatients(query.list());
			sm.closeSession();
		} catch( Exception exception){
			log.error("PatientLabelJobHandler: ", exception);
			throw exception;
		} finally {
			sm.closeSession();
		}
		return result;
	}

	private static class QueryBuilder {
		private StringBuilder queryStr;
		private List<Object> queryParams;
		private QueryBuilder() {
			queryStr = new StringBuilder();
			queryParams = new ArrayList<Object>();
		}
		
		public static QueryBuilder buildQuery(PatientLabelWizardState state) {
			QueryBuilder builder = new QueryBuilder();
			builder.append("select z from Patient as z " +
					"left join fetch z.person as pers " +
					"left join fetch z.account " +
					"left join fetch pers.homeAddress as loc " +
					"left join fetch loc.zipCode as zipCode " +
					"left join fetch zipCode.zip");
			ItemSeparator separator = new ItemSeparator(" where ", " and ");
			if (state.isLastName() && state.getLastNameFrom() != null && !state.getLastNameFrom().isEmpty()) {
				builder.append(separator.getSeparator());
				builder.append("(");
				if (state.getLastNameThrough() != null && !state.getLastNameThrough().isEmpty()) {
					builder.append("upper(z.person.lastName) between ? and ?");
					builder.addParam(state.getLastNameFrom().toUpperCase());
					builder.addParam(state.getLastNameThrough().toUpperCase());
				} else {
					builder.append("upper(z.person.lastName) like ?");
					builder.addParam(state.getLastNameFrom().toUpperCase() + "%");
				}
				builder.append(")");
			}
			
			if (state.isAccountNr() && state.getAccountNrFrom() != null) {
				builder.append(separator.getSeparator());
				builder.append("(");
				if (state.getAccountNrThrough() != null) {
					builder.append("z.account.id between ? and ?");
					builder.addParam(state.getAccountNrFrom());
					builder.addParam(state.getAccountNrThrough());
				} else {
					builder.append("z.account.id = ?");
					builder.addParam(state.getAccountNrFrom());
				}
				builder.append(")");
			}
			
			if (state.getSortBy() != null) {
				switch (state.getSortBy()) {
				case LAST_NAME:
					builder.append(" order by z.person.displayName asc");
					break;
				case ZIP_CODE:
					builder.append(" order by z.person.homeAddress.zipCode.zip.name asc");
					break;
				}
			}
			return builder;
		}
		
		private void append(String str) {
			queryStr.append(str);
		}
		
		private void addParam(Object param) {
			queryParams.add(param);
		}
		
		public String getQueryStr() {
			return queryStr.toString();
		}
		
		public List<Object> getQueryParams() {
			return Collections.unmodifiableList(queryParams);
		}
	}
}
